package com.jeasonzhao.report.engine.repo;

import java.lang.reflect.InvocationTargetException;
import java.util.HashSet;
import java.util.Hashtable;

import com.jeasonzhao.commons.utils.Algorithms;
import com.jeasonzhao.report.engine.ConfigurationValue;
import com.jeasonzhao.report.engine.impl.CSVDataSetProvider;
import com.jeasonzhao.report.engine.impl.DataSetProviderMessage;
import com.jeasonzhao.report.engine.impl.InternalBinaryDataSetProvider;
import com.jeasonzhao.report.engine.impl.SqlDataSetProvider;
import com.jeasonzhao.report.engine.irp.IDataSetProvider;

public class DataSetProviderRegistry
{
    private Hashtable<String,IDataSetProvider> m_register = new Hashtable<String,IDataSetProvider>();
    private HashSet<String> m_registerClasses = new HashSet<String>();
    private DataSetProviderRegistry()
    {
        try
        {
            register(SqlDataSetProvider.class);
            register(CSVDataSetProvider.class);
            register(InternalBinaryDataSetProvider.class);
        }
        catch(DataSetProviderRegistryException ex)
        {
        }
    }

    private static final DataSetProviderRegistry m_instance = new DataSetProviderRegistry();
    public static DataSetProviderRegistry getInstance()
    {
        return m_instance;
    }

    public synchronized DataSetProviderRegistry register(Class<? extends IDataSetProvider> cls,String ...alias)
        throws DataSetProviderRegistryException
    {
        try
        {
            if(null == cls || m_registerClasses.contains(cls.getName()))
            {
                return this;
            }
            m_registerClasses.add(cls.getName());
            java.lang.reflect.Constructor<? extends IDataSetProvider> c = cls.getConstructor();
            if(c == null)
            {
                throw new DataSetProviderRegistryException(DataSetProviderMessage.format(DataSetProviderMessage.MESSAGE_NO_DEFAULT_CONSTRUCTOR,cls));
            }
            IDataSetProvider instance = c.newInstance();
            ConfigurationValue cv = cls.getAnnotation(ConfigurationValue.class);
            String[] names = null;
            if(null == cv)
            {
                names = new String[]
                    {cls.getSimpleName()};
            }
            else
            {
                names = ((null == cv.value() ? "" : cv.value()) + "," + cls.getSimpleName()).split(",");
            }
            for(String s : names)
            {
                if(Algorithms.isEmpty(s))
                {
                    continue;
                }
                String key = s.trim().toLowerCase();
                if(m_register.containsKey(key))
                {
                    continue;
                }
                else
                {
                    m_register.put(key,instance);
                }
            }
            return this;
        }
        catch(InvocationTargetException ex)
        {
            throw new DataSetProviderRegistryException(ex);
        }
        catch(IllegalArgumentException ex)
        {
            throw new DataSetProviderRegistryException(ex);
        }
        catch(IllegalAccessException ex)
        {
            throw new DataSetProviderRegistryException(ex);
        }
        catch(InstantiationException ex)
        {
            throw new DataSetProviderRegistryException(ex);
        }
        catch(SecurityException ex)
        {
            throw new DataSetProviderRegistryException(ex);
        }
        catch(NoSuchMethodException ex)
        {
            throw new DataSetProviderRegistryException(ex);
        }
    }

    public IDataSetProvider get(String name)
    {
        if(Algorithms.isEmpty(name))
        {
            return null;
        }
        else
        {
            return m_register.get(name.toLowerCase().trim());
        }
    }
}
